
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>跨站请求伪造保护 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
    <link rel="next" title="数据库" href="databases.html" />
    <link rel="prev" title="Feed 聚合框架" href="contrib/syndication.html" />



 
<script src="../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);</script>

  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../index.html">Home</a>  |
        <a title="Table of contents" href="../contents.html">Table of contents</a>  |
        <a title="Global index" href="../genindex.html">Index</a>  |
        <a title="Module index" href="../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="contrib/syndication.html" title="Feed 聚合框架">previous</a>
     |
    <a href="index.html" title="API 参考" accesskey="U">up</a>
   |
    <a href="databases.html" title="数据库">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="ref-csrf">
            
  <div class="section" id="s-module-django.middleware.csrf">
<span id="s-cross-site-request-forgery-protection"></span><span id="module-django.middleware.csrf"></span><span id="cross-site-request-forgery-protection"></span><h1>跨站请求伪造保护<a class="headerlink" href="#module-django.middleware.csrf" title="永久链接至标题">¶</a></h1>
<p>CSRF 中间件和模板标签提供了易于使用的保护，防止 <a class="reference external" href="https://www.squarefree.com/securitytips/web-developers.html#CSRF">跨站请求伪造</a> 。 当一个恶意网站包含一个链接、一个表单按钮或一些 JavaScript，目的是在你的网站上执行一些操作，使用在浏览器中访问恶意网站的登录用户的凭证时，就会发生这种类型的攻击。 此外，还包括一种相关的攻击类型，“登录 CSRF”，即攻击网站欺骗用户的浏览器使用他人的凭证登录网站。</p>
<p>对 CSRF 攻击的第一道防线是确保 GET 请求（和其他“安全”方法，如 <span class="target" id="index-6"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc7231.html#section-4.2.1"><strong>RFC 7231#section-4.2.1</strong></a> 所定义的）没有副作用。通过“不安全”方法的请求，如 POST、PUT 和 DELETE，则可以通过以下步骤来保护。</p>
<div class="section" id="s-how-to-use-it">
<span id="s-using-csrf"></span><span id="how-to-use-it"></span><span id="using-csrf"></span><h2>如何使用它<a class="headerlink" href="#how-to-use-it" title="永久链接至标题">¶</a></h2>
<p>要在你的视图中利用 CSRF 保护，请遵循以下步骤：</p>
<ol class="arabic">
<li><p class="first">CSRF 中间件默认在 <a class="reference internal" href="settings.html#std:setting-MIDDLEWARE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">MIDDLEWARE</span></code></a> 配置中被激活。如果你覆盖了这个配置，请记住 <code class="docutils literal notranslate"><span class="pre">'django.middleware.csrf.CsrfViewMiddleware'</span></code> 应该排在任何假设 CSRF 攻击已经被处理的视图中间件之前。</p>
<p>如果你禁用了它，这并不推荐，你可以使用 <a class="reference internal" href="#django.views.decorators.csrf.csrf_protect" title="django.views.decorators.csrf.csrf_protect"><code class="xref py py-func docutils literal notranslate"><span class="pre">csrf_protect()</span></code></a> 对你想要保护的特定视图进行保护（见下文）。</p>
</li>
<li><p class="first">在任何使用 POST 表单的模板中，如果表单是针对内部 URL 的，请在 <code class="docutils literal notranslate"><span class="pre">&lt;form&gt;</span></code> 元素中使用 <a class="reference internal" href="templates/builtins.html#std:templatetag-csrf_token"><code class="xref std std-ttag docutils literal notranslate"><span class="pre">csrf_token</span></code></a> 标签，例如：</p>
<div class="highlight-html+django notranslate"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span><span class="cp">{%</span> <span class="k">csrf_token</span> <span class="cp">%}</span>
</pre></div>
</div>
<p>对于以外部 URL 为目标的 POST 表单，不应该这样做，因为这会导致 CSRF 令牌泄露，从而导致漏洞。</p>
</li>
<li><p class="first">在相应的视图函数中，确保 <a class="reference internal" href="templates/api.html#django.template.RequestContext" title="django.template.RequestContext"><code class="xref py py-class docutils literal notranslate"><span class="pre">RequestContext</span></code></a> 用于渲染响应，这样 <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">csrf_token</span> <span class="pre">%}</span></code> 才能正常工作。如果你使用的是 <a class="reference internal" href="../topics/http/shortcuts.html#django.shortcuts.render" title="django.shortcuts.render"><code class="xref py py-func docutils literal notranslate"><span class="pre">render()</span></code></a> 函数、通用视图或 contrib 应用程序，你已经被覆盖了，因为这些都使用 <code class="docutils literal notranslate"><span class="pre">RequestContext</span></code>。</p>
</li>
</ol>
<div class="section" id="s-ajax">
<span id="s-csrf-ajax"></span><span id="ajax"></span><span id="csrf-ajax"></span><h3>AJAX<a class="headerlink" href="#ajax" title="永久链接至标题">¶</a></h3>
<p>虽然上述方法可以用于 AJAX POST 请求，但它有一些不便之处：你必须记住在每个 POST 请求中都要把 CSRF 令牌作为 POST 数据传递进来。出于这个原因，有一种替代方法：在每个 XMLHttpRequest 上，设置一个自定义的 <code class="docutils literal notranslate"><span class="pre">X-CSRFToken</span></code> 头（由 <a class="reference internal" href="settings.html#std:setting-CSRF_HEADER_NAME"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_HEADER_NAME</span></code></a> 设置指定）为 CSRF 标记的值。这通常比较容易，因为许多 JavaScript 框架提供了钩子，允许在每个请求中设置头。</p>
<p>首先，你必须获得 CSRF 令牌。如何做取决于 <a class="reference internal" href="settings.html#std:setting-CSRF_USE_SESSIONS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code></a> 和 <a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_HTTPONLY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_HTTPONLY</span></code></a> 配置是否启用。</p>
<div class="section" id="s-acquiring-the-token-if-csrf-use-sessions-and-csrf-cookie-httponly-are-false">
<span id="s-acquiring-csrf-token-from-cookie"></span><span id="acquiring-the-token-if-csrf-use-sessions-and-csrf-cookie-httponly-are-false"></span><span id="acquiring-csrf-token-from-cookie"></span><h4>当 <a class="reference internal" href="settings.html#std:setting-CSRF_USE_SESSIONS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code></a> 和 <a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_HTTPONLY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_HTTPONLY</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 时获取令牌<a class="headerlink" href="#acquiring-the-token-if-csrf-use-sessions-and-csrf-cookie-httponly-are-false" title="永久链接至标题">¶</a></h4>
<p>推荐的令牌来源是 <code class="docutils literal notranslate"><span class="pre">csrftoken</span></code> cookie，如果你已经为你的视图启用了上文所述的 CSRF 保护，则会设置该 cookie。</p>
<p>CSRF 令牌 cookie 默认命名为 <code class="docutils literal notranslate"><span class="pre">csrftoken</span></code>，但你可以通过 <a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_NAME"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_NAME</span></code></a> 配置来控制 cookie 的名称。</p>
<p>你可以通过这样的方式获得令牌：</p>
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">function</span> <span class="nx">getCookie</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nx">cookieValue</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">&amp;&amp;</span> <span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">!==</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">cookies</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;;&#39;</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mf">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">cookies</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="kd">const</span> <span class="nx">cookie</span> <span class="o">=</span> <span class="nx">cookies</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">trim</span><span class="p">();</span>
            <span class="c1">// Does this cookie string begin with the name we want?</span>
            <span class="k">if</span> <span class="p">(</span><span class="nx">cookie</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span> <span class="nx">name</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mf">1</span><span class="p">)</span> <span class="o">===</span> <span class="p">(</span><span class="nx">name</span> <span class="o">+</span> <span class="s1">&#39;=&#39;</span><span class="p">))</span> <span class="p">{</span>
                <span class="nx">cookieValue</span> <span class="o">=</span> <span class="nb">decodeURIComponent</span><span class="p">(</span><span class="nx">cookie</span><span class="p">.</span><span class="nx">substring</span><span class="p">(</span><span class="nx">name</span><span class="p">.</span><span class="nx">length</span> <span class="o">+</span> <span class="mf">1</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="nx">cookieValue</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">csrftoken</span> <span class="o">=</span> <span class="nx">getCookie</span><span class="p">(</span><span class="s1">&#39;csrftoken&#39;</span><span class="p">);</span>
</pre></div>
</div>
<p>上述代码可以通过使用 <a class="reference external" href="https://github.com/js-cookie/js-cookie/">JavaScript Cookie 库</a> 代替 <code class="docutils literal notranslate"><span class="pre">getCookie</span></code> 来简化：</p>
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span> <span class="nx">csrftoken</span> <span class="o">=</span> <span class="nx">Cookies</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;csrftoken&#39;</span><span class="p">);</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">CSRF 令牌也存在于 DOM 中，但只有在模板中使用 <a class="reference internal" href="templates/builtins.html#std:templatetag-csrf_token"><code class="xref std std-ttag docutils literal notranslate"><span class="pre">csrf_token</span></code></a> 明确包含时才会出现。Cookie 包含了规范的令牌；<code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 更倾向于使用 cookie 而不是 DOM 中的令牌。无论如何，如果 DOM 中存在令牌，你就能保证拥有 cookie，所以你应该使用 cookie！</p>
</div>
<div class="admonition warning">
<p class="first admonition-title">警告</p>
<p class="last">如果你的视图没有渲染包含 <a class="reference internal" href="templates/builtins.html#std:templatetag-csrf_token"><code class="xref std std-ttag docutils literal notranslate"><span class="pre">csrf_token</span></code></a> 模板标签的模板，Django 可能不会设置 CSRF 令牌 cookie。这种情况常见于表单被动态添加到页面的情况。针对这种情况，Django 提供了一个视图装饰器来强制设置 cookie： <code class="xref py py-func docutils literal notranslate"><span class="pre">sure_csrf_cookie()</span></code>。</p>
</div>
</div>
<div class="section" id="s-acquiring-the-token-if-csrf-use-sessions-or-csrf-cookie-httponly-is-true">
<span id="s-acquiring-csrf-token-from-html"></span><span id="acquiring-the-token-if-csrf-use-sessions-or-csrf-cookie-httponly-is-true"></span><span id="acquiring-csrf-token-from-html"></span><h4>当 <a class="reference internal" href="settings.html#std:setting-CSRF_USE_SESSIONS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code></a> 或 <a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_HTTPONLY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_HTTPONLY</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 时获取令牌<a class="headerlink" href="#acquiring-the-token-if-csrf-use-sessions-or-csrf-cookie-httponly-is-true" title="永久链接至标题">¶</a></h4>
<p>如果你激活了 <a class="reference internal" href="settings.html#std:setting-CSRF_USE_SESSIONS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code></a> 或 <a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_HTTPONLY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_HTTPONLY</span></code></a>，你必须在你的 HTML 中包含 CSRF 令牌，并通过 JavaScript 从 DOM 中读取该令牌：</p>
<div class="highlight-html+django notranslate"><div class="highlight"><pre><span></span><span class="cp">{%</span> <span class="k">csrf_token</span> <span class="cp">%}</span>
<span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
<span class="kd">const</span> <span class="nx">csrftoken</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;[name=csrfmiddlewaretoken]&#39;</span><span class="p">).</span><span class="nx">value</span><span class="p">;</span>
<span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</pre></div>
</div>
</div>
<div class="section" id="s-setting-the-token-on-the-ajax-request">
<span id="setting-the-token-on-the-ajax-request"></span><h4>在 AJAX 请求中设置令牌<a class="headerlink" href="#setting-the-token-on-the-ajax-request" title="永久链接至标题">¶</a></h4>
<p>最后，你需要在 AJAX 请求中设置头。使用 <a class="reference external" href="https://developer.mozilla.org/en-US/docs/Web/API/fetch">fetch()</a> API：</p>
<div class="highlight-javascript notranslate"><div class="highlight"><pre><span></span><span class="kd">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Request</span><span class="p">(</span>
    <span class="cm">/* URL */</span><span class="p">,</span>
    <span class="p">{</span><span class="nx">headers</span><span class="o">:</span> <span class="p">{</span><span class="s1">&#39;X-CSRFToken&#39;</span><span class="o">:</span> <span class="nx">csrftoken</span><span class="p">}}</span>
<span class="p">);</span>
<span class="nx">fetch</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="p">{</span>
    <span class="nx">method</span><span class="o">:</span> <span class="s1">&#39;POST&#39;</span><span class="p">,</span>
    <span class="nx">mode</span><span class="o">:</span> <span class="s1">&#39;same-origin&#39;</span>  <span class="c1">// Do not send CSRF token to another domain.</span>
<span class="p">}).</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// ...</span>
<span class="p">});</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="s-using-csrf-in-jinja2-templates">
<span id="using-csrf-in-jinja2-templates"></span><h3>在 Jinja2 模板中使用 CSRF<a class="headerlink" href="#using-csrf-in-jinja2-templates" title="永久链接至标题">¶</a></h3>
<p>Django 的 <a class="reference internal" href="../topics/templates.html#django.template.backends.jinja2.Jinja2" title="django.template.backends.jinja2.Jinja2"><code class="xref py py-class docutils literal notranslate"><span class="pre">Jinja2</span></code></a> 模板后端在所有模板的上下文中添加了 <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">csrf_input</span> <span class="pre">}}</span></code>，相当于 Django 模板语言中的 <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">csrf_token</span> <span class="pre">%}</span></code>。例如：</p>
<div class="highlight-html+jinja notranslate"><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;post&quot;</span><span class="p">&gt;</span><span class="cp">{{</span> <span class="nv">csrf_input</span> <span class="cp">}}</span>
</pre></div>
</div>
</div>
<div class="section" id="s-module-django.views.decorators.csrf">
<span id="s-the-decorator-method"></span><span id="module-django.views.decorators.csrf"></span><span id="the-decorator-method"></span><h3>装饰器方法<a class="headerlink" href="#module-django.views.decorators.csrf" title="永久链接至标题">¶</a></h3>
<p>与其添加 <code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 作为全面保护，不如在需要保护的特定视图上使用 <code class="docutils literal notranslate"><span class="pre">csrf_protect</span></code> 装饰器，它具有完全相同的功能。它必须用于 <strong>同时</strong> 在输出中插入 CSRF 令牌的视图和接受 POST 表单数据的视图。（这些通常是相同的视图函数，但并不总是如此）。</p>
<p><strong>不建议</strong> 单独使用装饰器，因为如果忘记使用，就会出现安全漏洞。“腰带和支架”的策略，两者同时使用也可以，而且会产生最小的开销。</p>
<dl class="function">
<dt id="django.views.decorators.csrf.csrf_protect">
<code class="descname">csrf_protect</code>(<em>view</em>)<a class="headerlink" href="#django.views.decorators.csrf.csrf_protect" title="永久链接至目标">¶</a></dt>
<dd><p>为视图提供 <code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 保护的装饰器。</p>
<p>用法：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="kn">from</span> <span class="nn">django.views.decorators.csrf</span> <span class="kn">import</span> <span class="n">csrf_protect</span>

<span class="nd">@csrf_protect</span>
<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">c</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="c1"># ...</span>
    <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s2">&quot;a_template.html&quot;</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span>
</pre></div>
</div>
<p>如果你使用的是基于类的视图，你可以参考 <a class="reference internal" href="../topics/class-based-views/intro.html#id1"><span class="std std-ref">装饰基于类的视图</span></a>。</p>
</dd></dl>

</div>
</div>
<div class="section" id="s-rejected-requests">
<span id="s-csrf-rejected-requests"></span><span id="rejected-requests"></span><span id="csrf-rejected-requests"></span><h2>被拒绝的请求<a class="headerlink" href="#rejected-requests" title="永久链接至标题">¶</a></h2>
<p>默认情况下，如果传入的请求未能通过 <code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 执行的检查，则会向用户发送“403 Forbidden”响应。 这通常只应该出现在真正的跨站点请求伪造时，或者由于编程错误，CSRF 令牌没有被包含在 POST 表单中。</p>
<p>然而，错误页面不是很友好，所以你可能想提供自己的视图来处理这种情况。 要做到这一点，请设置 <a class="reference internal" href="settings.html#std:setting-CSRF_FAILURE_VIEW"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_FAILURE_VIEW</span></code></a> 配置。</p>
<p>CSRF 失败会被记录为警告到 <a class="reference internal" href="../topics/logging.html#django-security-logger"><span class="std std-ref">django.security.csrf</span></a> 记录器。</p>
</div>
<div class="section" id="s-how-it-works">
<span id="s-how-csrf-works"></span><span id="how-it-works"></span><span id="how-csrf-works"></span><h2>工作方式<a class="headerlink" href="#how-it-works" title="永久链接至标题">¶</a></h2>
<p>CSRF 保护是基于以下几点：</p>
<ol class="arabic">
<li><p class="first">一个基于随机密钥值的 CSRF cookie，其他网站无法访问。</p>
<p>这个 cookie 是由 <code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 设置的。如果在请求中还没有设置的话，那么它将与调用了 <code class="docutils literal notranslate"><span class="pre">django.middleware.csrf.get_token()</span></code> （内部用于获取 CSRF 令牌的函数）的每个响应一起发送。</p>
<p>为了防止 <a class="reference external" href="http://breachattack.com/">BREACH</a> 攻击，令牌不是简单的密钥，而是在密钥前面加上一个随机掩码，用来扰乱密钥。</p>
<p>出于安全考虑，每次用户登录时都会改变密钥的值。</p>
</li>
<li><p class="first">一个隐藏的表单字段，名称为“csrfmiddlewaretoken”，存在于所有发出的 POST 表单中。这个字段的值也是密钥的值，但有一个掩码，这个掩码会被添加到字段中，并被用来扰乱字段。掩码在每次调用 <code class="docutils literal notranslate"><span class="pre">get_token()</span></code> 时都会重新生成，所以表单字段的值在每次响应时都会改变。</p>
<p>这一部分是由模板标签来完成的。</p>
</li>
<li><p class="first">对于所有不使用 HTTP GET、HEAD、OPTIONS 或 TRACE 的传入请求，必须存在一个 CSRF cookie，并且“csrfmiddlewaretoken”字段必须存在且正确。如果不存在，用户将得到一个 403 错误。</p>
<p>当验证“csrfmiddlewaretoken”字段值时，只有密钥，而不是完整的令牌，会与 cookie 值中的密钥进行比较。这允许使用不断变化的令牌。虽然每个请求都可能使用自己的令牌，但密钥对所有请求都是通用的。</p>
<p>这个检查是由 <code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 完成的。</p>
</li>
<li><p class="first">此外，对于 HTTPS 请求，<code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 会进行严格的 referer 检查。这意味着即使一个子域可以在你的域上设置或修改 cookie，它也不能强迫用户向你的应用程序提交，因为该请求不会来自你自己的确切域。</p>
<p>这也解决了在 HTTPS 下使用独立于会话的密钥时可能出现的中间人攻击问题，这是因为 HTTP <code class="docutils literal notranslate"><span class="pre">Set-Cookie</span></code> 头会被客户接受（不幸的是），即使他们在 HTTPS 下与一个网站对话。对 HTTP 请求不进行 Referer 检查，因为 HTTP 下 <code class="docutils literal notranslate"><span class="pre">Referer</span></code> 头的存在不够可靠）。</p>
<p>如果设置了 <a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_DOMAIN"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_DOMAIN</span></code></a> 设置，则会将 referer 与之进行比较。你可以通过包含一个前导点号来允许跨子域请求。例如，<code class="docutils literal notranslate"><span class="pre">CSRF_COOKIE_DOMAIN</span> <span class="pre">=</span> <span class="pre">'.example.com'</span></code> 将允许来自 <code class="docutils literal notranslate"><span class="pre">www.example.com</span></code> 和 <code class="docutils literal notranslate"><span class="pre">api.example.com</span></code> 的 POST 请求。如果没有设置，那么 referer 必须与 HTTP <code class="docutils literal notranslate"><span class="pre">Host</span></code> 头匹配。</p>
<p>通过 <a class="reference internal" href="settings.html#std:setting-CSRF_TRUSTED_ORIGINS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_TRUSTED_ORIGINS</span></code></a> 设置，可以将接受的 referer 扩展到当前主机或 cookie 域之外。</p>
</li>
</ol>
<p>这确保了只有源自受信任域的表单才能用于 POST 回数据。</p>
<p>它故意忽略了 GET 请求（以及被 <span class="target" id="index-7"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc7231.html#section-4.2.1"><strong>RFC 7231#section-4.2.1</strong></a> 定义为“安全”的其他请求）。<span class="target" id="index-8"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc7231.html#section-4.2.1"><strong>RFC 7231#section-4.2.1</strong></a> 将 POST、PUT 和 DELETE 定义为“不安全”，所有其他方法也被认为是不安全的，以获得最大的保护。</p>
<p>CSRF 保护不能防止中间人攻击，所以使用 <a class="reference internal" href="../topics/security.html#security-recommendation-ssl"><span class="std std-ref">HTTPS</span></a> 与 <a class="reference internal" href="middleware.html#http-strict-transport-security"><span class="std std-ref">HTTP 严格传输安全</span></a>。它还假设 <a class="reference internal" href="../topics/security.html#host-headers-virtual-hosting"><span class="std std-ref">验证 HOST 头</span></a> 和你的网站上没有任何 <a class="reference internal" href="../topics/security.html#cross-site-scripting"><span class="std std-ref">跨站脚本漏洞</span></a> （因为 XSS 漏洞已经让攻击者做了 CSRF 漏洞允许的任何事情，甚至更糟）。</p>
<div class="admonition-removing-the-referer-header admonition">
<p class="first admonition-title">删除 <code class="docutils literal notranslate"><span class="pre">Referer</span></code> 头</p>
<p class="last">为了避免向第三方网站透露 referrer URL，你可能想在你的网站的 <code class="docutils literal notranslate"><span class="pre">&lt;a&gt;</span></code> 标签上 <a class="reference external" href="https://www.w3.org/TR/referrer-policy/#referrer-policy-delivery">禁用 referrer</a> 。例如，你可以使用 <code class="docutils literal notranslate"><span class="pre">&lt;meta</span> <span class="pre">name=&quot;referrer&quot;</span> <span class="pre">content=&quot;no-referrer&quot;&gt;</span></code> 标签或包含 <code class="docutils literal notranslate"><span class="pre">Referrer-Policy:</span> <span class="pre">no-referrer</span></code> 头。由于 CSRF 保护对 HTTPS 请求进行严格的 referer 检查，这些技术会在使用“不安全”方法的请求上导致 CSRF 失败。取而代之的是，使用诸如 <code class="docutils literal notranslate"><span class="pre">&lt;a</span> <span class="pre">rel=&quot;noreferrer&quot;</span> <span class="pre">...&gt;&quot;</span></code> 这样的替代品来链接第三方网站。</p>
</div>
</div>
<div class="section" id="s-caching">
<span id="caching"></span><h2>缓存<a class="headerlink" href="#caching" title="永久链接至标题">¶</a></h2>
<p>如果 <a class="reference internal" href="templates/builtins.html#std:templatetag-csrf_token"><code class="xref std std-ttag docutils literal notranslate"><span class="pre">csrf_token</span></code></a> 模板标签被模板使用（或 <code class="docutils literal notranslate"><span class="pre">get_token</span></code> 函数被其他方式调用），<code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 将添加一个 cookie 和一个 <code class="docutils literal notranslate"><span class="pre">Vary:</span> <span class="pre">Cookie</span></code> 头到响应中。这意味着，如果按照指示使用，中间件将与缓存中间件很好地配合（<code class="docutils literal notranslate"><span class="pre">UpdateCacheMiddleware</span></code> 先于所有其他中间件）。</p>
<p>但是，如果你在单个视图上使用缓存装饰器，CSRF 中间件还不能设置 Vary 头或 CSRF cookie，响应将在没有任何一个的情况下被缓存。在这种情况下，在任何需要插入 CSRF 令牌的视图上，你应该先使用 <a class="reference internal" href="#django.views.decorators.csrf.csrf_protect" title="django.views.decorators.csrf.csrf_protect"><code class="xref py py-func docutils literal notranslate"><span class="pre">django.views.decorators.csrf.csrf_protect()</span></code></a> 装饰器：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.views.decorators.cache</span> <span class="kn">import</span> <span class="n">cache_page</span>
<span class="kn">from</span> <span class="nn">django.views.decorators.csrf</span> <span class="kn">import</span> <span class="n">csrf_protect</span>

<span class="nd">@cache_page</span><span class="p">(</span><span class="mi">60</span> <span class="o">*</span> <span class="mi">15</span><span class="p">)</span>
<span class="nd">@csrf_protect</span>
<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="o">...</span>
</pre></div>
</div>
<p>如果你使用的是基于类的视图，你可以参考 <a class="reference internal" href="../topics/class-based-views/intro.html#id1"><span class="std std-ref">装饰基于类的视图</span></a>。</p>
</div>
<div class="section" id="s-testing">
<span id="testing"></span><h2>测试中<a class="headerlink" href="#testing" title="永久链接至标题">¶</a></h2>
<p><code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code> 通常会成为测试视图功能的一大障碍，因为需要 CSRF 令牌，而 CSRF 令牌必须在每个 POST 请求中发送。 出于这个原因，Django 的 HTTP 测试客户端已经被修改为在请求中设置一个标志，放松中间件和 <code class="docutils literal notranslate"><span class="pre">csrf_protect</span></code> 装饰器，使它们不再拒绝请求。 在其他方面（如发送 cookie 等），它们的行为是一样的。</p>
<p>如果出于某种原因，你 <em>想</em> 让测试客户端执行 CSRF 检查，你可以创建一个执行 CSRF 检查的测试客户端实例：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">Client</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">csrf_client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="n">enforce_csrf_checks</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-limitations">
<span id="s-csrf-limitations"></span><span id="limitations"></span><span id="csrf-limitations"></span><h2>限制<a class="headerlink" href="#limitations" title="永久链接至标题">¶</a></h2>
<p>一个网站内的子域将能够在客户端设置整个域的 cookie。 通过设置 cookie 并使用相应的令牌，子域将能够规避 CSRF 保护。 避免这种情况的唯一方法是确保子域由受信任的用户控制（或者，至少无法设置 cookie）。 需要注意的是，即使没有 CSRF，也存在其他漏洞，比如会话固定，将子域交给不受信任的一方是个坏主意，而这些漏洞在目前的浏览器上是不容易修复的。</p>
</div>
<div class="section" id="s-edge-cases">
<span id="edge-cases"></span><h2>边缘案例<a class="headerlink" href="#edge-cases" title="永久链接至标题">¶</a></h2>
<p>某些视图可能有不寻常的要求，这意味着它们不符合这里所设想的正常模式。在这些情况下，一些实用程序可能很有用。下一节将介绍可能需要它们的情况。</p>
<div class="section" id="s-utilities">
<span id="utilities"></span><h3>实用程序<a class="headerlink" href="#utilities" title="永久链接至标题">¶</a></h3>
<p>下面的例子假设你使用的是基于函数的视图。如果你正在使用基于类的视图，你可以参考 <a class="reference internal" href="../topics/class-based-views/intro.html#id1"><span class="std std-ref">装饰基于类的视图</span></a>。</p>
<dl class="function">
<dt id="django.views.decorators.csrf.csrf_exempt">
<code class="descname">csrf_exempt</code>(<em>view</em>)<a class="headerlink" href="#django.views.decorators.csrf.csrf_exempt" title="永久链接至目标">¶</a></dt>
<dd><p>该装饰器标记着一个视图被免除了中间件所确保的保护。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponse</span>
<span class="kn">from</span> <span class="nn">django.views.decorators.csrf</span> <span class="kn">import</span> <span class="n">csrf_exempt</span>

<span class="nd">@csrf_exempt</span>
<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s1">&#39;Hello world&#39;</span><span class="p">)</span>
</pre></div>
</div>
</dd></dl>

<dl class="function">
<dt id="django.views.decorators.csrf.requires_csrf_token">
<code class="descname">requires_csrf_token</code>(<em>view</em>)<a class="headerlink" href="#django.views.decorators.csrf.requires_csrf_token" title="永久链接至目标">¶</a></dt>
<dd><p>通常情况下，如果 <code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware.process_view</span></code> 或类似 <code class="docutils literal notranslate"><span class="pre">csrf_protect</span></code> 这样的等价物没有运行， <a class="reference internal" href="templates/builtins.html#std:templatetag-csrf_token"><code class="xref std std-ttag docutils literal notranslate"><span class="pre">csrf_token</span></code></a> 模板标签将无法工作。视图装饰器 <code class="docutils literal notranslate"><span class="pre">requires_csrf_token</span></code> 可以用来确保模板标签工作。这个装饰器的工作原理与 <code class="docutils literal notranslate"><span class="pre">csrf_protect</span></code> 类似，但绝不会拒绝接收到的请求。</p>
<p>举例：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="kn">from</span> <span class="nn">django.views.decorators.csrf</span> <span class="kn">import</span> <span class="n">requires_csrf_token</span>

<span class="nd">@requires_csrf_token</span>
<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">c</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="c1"># ...</span>
    <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s2">&quot;a_template.html&quot;</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span>
</pre></div>
</div>
</dd></dl>

<dl class="function">
<dt id="django.views.decorators.csrf.ensure_csrf_cookie">
<code class="descname">ensure_csrf_cookie</code>(<em>view</em>)<a class="headerlink" href="#django.views.decorators.csrf.ensure_csrf_cookie" title="永久链接至目标">¶</a></dt>
<dd><p>该装饰器强制视图发送 CSRF cookie。</p>
</dd></dl>

</div>
<div class="section" id="s-scenarios">
<span id="scenarios"></span><h3>情境<a class="headerlink" href="#scenarios" title="永久链接至标题">¶</a></h3>
<div class="section" id="s-csrf-protection-should-be-disabled-for-just-a-few-views">
<span id="csrf-protection-should-be-disabled-for-just-a-few-views"></span><h4>仅仅是几个视图就应该禁用 CSRF 保护。<a class="headerlink" href="#csrf-protection-should-be-disabled-for-just-a-few-views" title="永久链接至标题">¶</a></h4>
<p>大多数视图需要 CSRF 保护，但也有少数视图不需要。</p>
<p>解决办法：与其禁用中间件并对所有需要的视图应用 <code class="docutils literal notranslate"><span class="pre">csrf_protect</span></code>，不如启用中间件并使用 <code class="xref py py-func docutils literal notranslate"><span class="pre">csrf_exempt()</span></code>。</p>
</div>
<div class="section" id="s-csrfviewmiddleware-process-view-not-used">
<span id="csrfviewmiddleware-process-view-not-used"></span><h4>CsrfViewMiddleware.process_view 没有使用<a class="headerlink" href="#csrfviewmiddleware-process-view-not-used" title="永久链接至标题">¶</a></h4>
<p>有些情况下，<code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware.process_view</span></code> 可能在你的视图运行之前没有运行——例如 404 和 500 处理程序——但你仍然需要表单中的 CSRF 令牌。</p>
<p>解决方法：使用 <code class="xref py py-func docutils literal notranslate"><span class="pre">requests_csrf_token()</span></code>。</p>
</div>
<div class="section" id="s-unprotected-view-needs-the-csrf-token">
<span id="unprotected-view-needs-the-csrf-token"></span><h4>不受保护的视图需要 CSRF 令牌<a class="headerlink" href="#unprotected-view-needs-the-csrf-token" title="永久链接至标题">¶</a></h4>
<p>可能有一些视图是不受保护的，已经被 <code class="docutils literal notranslate"><span class="pre">csrf_exempt</span></code> 豁免，但仍然需要包括 CSRF 令牌。</p>
<p>解决方法：使用 <a class="reference internal" href="#django.views.decorators.csrf.csrf_exempt" title="django.views.decorators.csrf.csrf_exempt"><code class="xref py py-func docutils literal notranslate"><span class="pre">csrf_exempt()</span></code></a> 后面跟着 <a class="reference internal" href="#django.views.decorators.csrf.requires_csrf_token" title="django.views.decorators.csrf.requires_csrf_token"><code class="xref py py-func docutils literal notranslate"><span class="pre">requires_csrf_token()</span></code></a>。（即 <code class="docutils literal notranslate"><span class="pre">requires_csrf_token</span></code> 应该是最里面的装饰器)。</p>
</div>
<div class="section" id="s-view-needs-protection-for-one-path">
<span id="view-needs-protection-for-one-path"></span><h4>视图需要保护一条路径<a class="headerlink" href="#view-needs-protection-for-one-path" title="永久链接至标题">¶</a></h4>
<p>一个视图只在一组条件下需要 CSRF 保护，其余时间一定不能有。</p>
<p>解决方法：用 <code class="xref py py-func docutils literal notranslate"><span class="pre">csrf_exempt()</span></code> 表示整个视图函数，用 <code class="xref py py-func docutils literal notranslate"><span class="pre">csrf_protect()</span></code> 表示其中需要保护的路径。例如：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.views.decorators.csrf</span> <span class="kn">import</span> <span class="n">csrf_exempt</span><span class="p">,</span> <span class="n">csrf_protect</span>

<span class="nd">@csrf_exempt</span>
<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>

    <span class="nd">@csrf_protect</span>
    <span class="k">def</span> <span class="nf">protected_path</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
        <span class="n">do_something</span><span class="p">()</span>

    <span class="k">if</span> <span class="n">some_condition</span><span class="p">():</span>
       <span class="k">return</span> <span class="n">protected_path</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
       <span class="n">do_something_else</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="s-page-uses-ajax-without-any-html-form">
<span id="page-uses-ajax-without-any-html-form"></span><h4>页面使用 AJAX，没有任何 HTML 表单<a class="headerlink" href="#page-uses-ajax-without-any-html-form" title="永久链接至标题">¶</a></h4>
<p>一个页面通过 AJAX 进行 POST 请求，而该页面并没有一个带有 <a class="reference internal" href="templates/builtins.html#std:templatetag-csrf_token"><code class="xref std std-ttag docutils literal notranslate"><span class="pre">csrf_token</span></code></a> 的 HTML 表单，这将导致所需的 CSRF cookie 被发送。</p>
<p>解决方法：在发送页面的视图上使用 <code class="xref py py-func docutils literal notranslate"><span class="pre">sure_csrf_cookie()</span></code>。</p>
</div>
</div>
</div>
<div class="section" id="s-contrib-and-reusable-apps">
<span id="contrib-and-reusable-apps"></span><h2>Contrib 和可重用的应用<a class="headerlink" href="#contrib-and-reusable-apps" title="永久链接至标题">¶</a></h2>
<p>因为开发者可以关闭 <code class="docutils literal notranslate"><span class="pre">CsrfViewMiddleware</span></code>，所以 contrib 应用程序中的所有相关视图都使用 <code class="docutils literal notranslate"><span class="pre">csrf_protect</span></code> 装饰器来确保这些应用程序对 CSRF 的安全性。 建议其他可重用应用的开发者，如果想要得到同样的保证，也在他们的视图上使用 <code class="docutils literal notranslate"><span class="pre">csrf_protect</span></code> 装饰器。</p>
</div>
<div class="section" id="s-settings">
<span id="settings"></span><h2>配置<a class="headerlink" href="#settings" title="永久链接至标题">¶</a></h2>
<p>一些配置可以用来控制Django 的 CSRF 行为：</p>
<ul class="simple">
<li><a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_AGE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_AGE</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_DOMAIN"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_DOMAIN</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_HTTPONLY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_HTTPONLY</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_NAME"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_NAME</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_PATH"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_PATH</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_SAMESITE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_SAMESITE</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_COOKIE_SECURE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_COOKIE_SECURE</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_FAILURE_VIEW"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_FAILURE_VIEW</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_HEADER_NAME"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_HEADER_NAME</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_TRUSTED_ORIGINS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_TRUSTED_ORIGINS</span></code></a></li>
<li><a class="reference internal" href="settings.html#std:setting-CSRF_USE_SESSIONS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code></a></li>
</ul>
</div>
<div class="section" id="s-frequently-asked-questions">
<span id="frequently-asked-questions"></span><h2>常问问题<a class="headerlink" href="#frequently-asked-questions" title="永久链接至标题">¶</a></h2>
<div class="section" id="s-is-posting-an-arbitrary-csrf-token-pair-cookie-and-post-data-a-vulnerability">
<span id="is-posting-an-arbitrary-csrf-token-pair-cookie-and-post-data-a-vulnerability"></span><h3>可以提交任意的 CSRF 令牌对（cookie 和 POST 数据）是漏洞吗？<a class="headerlink" href="#is-posting-an-arbitrary-csrf-token-pair-cookie-and-post-data-a-vulnerability" title="永久链接至标题">¶</a></h3>
<p>不，这是设计好的。如果没有中间人攻击，攻击者就没有办法向受害者的浏览器发送 CSRF 令牌 cookie，所以成功的攻击需要通过 XSS 或类似的方式获得受害者浏览器的 cookie，在这种情况下，攻击者通常不需要 CSRF 攻击。</p>
<p>一些安全审计工具将此标记为问题，但如前所述，攻击者无法窃取用户浏览器的 CSRF cookie。使用 Firebug、Chrome 开发工具等“窃取”或修改 <em>自己的</em> 令牌并不是漏洞。</p>
</div>
<div class="section" id="s-is-it-a-problem-that-django-s-csrf-protection-isn-t-linked-to-a-session-by-default">
<span id="is-it-a-problem-that-django-s-csrf-protection-isn-t-linked-to-a-session-by-default"></span><h3>Django 的 CSRF 保护默认不与会话关联，是不是有问题？<a class="headerlink" href="#is-it-a-problem-that-django-s-csrf-protection-isn-t-linked-to-a-session-by-default" title="永久链接至标题">¶</a></h3>
<p>不，这是设计好的。不将 CSRF 保护与会话联系起来，就可以在诸如 <em>pastebin</em> 这样允许匿名用户提交的网站上使用保护，而这些用户并没有会话。</p>
<p>如果你希望在用户的会话中存储 CSRF 令牌，请使用 <a class="reference internal" href="settings.html#std:setting-CSRF_USE_SESSIONS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code></a> 设置。</p>
</div>
<div class="section" id="s-why-might-a-user-encounter-a-csrf-validation-failure-after-logging-in">
<span id="why-might-a-user-encounter-a-csrf-validation-failure-after-logging-in"></span><h3>为什么用户登录后会遇到 CSRF 验证失败？<a class="headerlink" href="#why-might-a-user-encounter-a-csrf-validation-failure-after-logging-in" title="永久链接至标题">¶</a></h3>
<p>出于安全考虑，每次用户登录时，CSRF 令牌都会轮换。任何在登录前生成表单的页面都会有一个旧的、无效的 CSRF 令牌，需要重新加载。如果用户在登录后使用后退按钮或在不同的浏览器标签页中登录，可能会发生这种情况。</p>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">跨站请求伪造保护</a><ul>
<li><a class="reference internal" href="#how-to-use-it">如何使用它</a><ul>
<li><a class="reference internal" href="#ajax">AJAX</a><ul>
<li><a class="reference internal" href="#acquiring-the-token-if-csrf-use-sessions-and-csrf-cookie-httponly-are-false">当 <code class="docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code> 和 <code class="docutils literal notranslate"><span class="pre">CSRF_COOKIE_HTTPONLY</span></code> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 时获取令牌</a></li>
<li><a class="reference internal" href="#acquiring-the-token-if-csrf-use-sessions-or-csrf-cookie-httponly-is-true">当 <code class="docutils literal notranslate"><span class="pre">CSRF_USE_SESSIONS</span></code> 或 <code class="docutils literal notranslate"><span class="pre">CSRF_COOKIE_HTTPONLY</span></code> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 时获取令牌</a></li>
<li><a class="reference internal" href="#setting-the-token-on-the-ajax-request">在 AJAX 请求中设置令牌</a></li>
</ul>
</li>
<li><a class="reference internal" href="#using-csrf-in-jinja2-templates">在 Jinja2 模板中使用 CSRF</a></li>
<li><a class="reference internal" href="#module-django.views.decorators.csrf">装饰器方法</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rejected-requests">被拒绝的请求</a></li>
<li><a class="reference internal" href="#how-it-works">工作方式</a></li>
<li><a class="reference internal" href="#caching">缓存</a></li>
<li><a class="reference internal" href="#testing">测试中</a></li>
<li><a class="reference internal" href="#limitations">限制</a></li>
<li><a class="reference internal" href="#edge-cases">边缘案例</a><ul>
<li><a class="reference internal" href="#utilities">实用程序</a></li>
<li><a class="reference internal" href="#scenarios">情境</a><ul>
<li><a class="reference internal" href="#csrf-protection-should-be-disabled-for-just-a-few-views">仅仅是几个视图就应该禁用 CSRF 保护。</a></li>
<li><a class="reference internal" href="#csrfviewmiddleware-process-view-not-used">CsrfViewMiddleware.process_view 没有使用</a></li>
<li><a class="reference internal" href="#unprotected-view-needs-the-csrf-token">不受保护的视图需要 CSRF 令牌</a></li>
<li><a class="reference internal" href="#view-needs-protection-for-one-path">视图需要保护一条路径</a></li>
<li><a class="reference internal" href="#page-uses-ajax-without-any-html-form">页面使用 AJAX，没有任何 HTML 表单</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#contrib-and-reusable-apps">Contrib 和可重用的应用</a></li>
<li><a class="reference internal" href="#settings">配置</a></li>
<li><a class="reference internal" href="#frequently-asked-questions">常问问题</a><ul>
<li><a class="reference internal" href="#is-posting-an-arbitrary-csrf-token-pair-cookie-and-post-data-a-vulnerability">可以提交任意的 CSRF 令牌对（cookie 和 POST 数据）是漏洞吗？</a></li>
<li><a class="reference internal" href="#is-it-a-problem-that-django-s-csrf-protection-isn-t-linked-to-a-session-by-default">Django 的 CSRF 保护默认不与会话关联，是不是有问题？</a></li>
<li><a class="reference internal" href="#why-might-a-user-encounter-a-csrf-validation-failure-after-logging-in">为什么用户登录后会遇到 CSRF 验证失败？</a></li>
</ul>
</li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="contrib/syndication.html"
                        title="上一章">Feed 聚合框架</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="databases.html"
                        title="下一章">数据库</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../_sources/ref/csrf.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="contrib/syndication.html" title="Feed 聚合框架">previous</a>
     |
    <a href="index.html" title="API 参考" accesskey="U">up</a>
   |
    <a href="databases.html" title="数据库">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>